﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BMLib;

namespace BrainMatch
{
    public class HisClassify : IWaveClassify
    {
        private WaveManager m_Manager = null;

        private Bitmap m_Bitmap = new Bitmap(128, 128, PixelFormat.Format24bppRgb);
        private Pen m_Pen = new Pen(Color.White, 1);
        public HisClassify(WaveManager manager)
        {
            m_Manager = manager;
        }

        public string GetFingerData(WaveItem item)
        {
            Graphics g = Graphics.FromImage(m_Bitmap);
            g.Clear(Color.Black);
            item.DrawToBitmap(m_Bitmap, m_Pen);

            int[] datah = new int[m_Bitmap.Width];
            int[] datav = new int[m_Bitmap.Width];

            BitmapData bitmapdata = m_Bitmap.LockBits(new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height), ImageLockMode.ReadOnly, m_Bitmap.PixelFormat);

            unsafe
            {
                byte* bits = (byte*)bitmapdata.Scan0;

                for (int x = 0; x < bitmapdata.Width; x++)
                {
                    for (int y = 0; y < bitmapdata.Height; y++)
                    {
                        int index = y * bitmapdata.Stride + x * 3;
                        if (bits[index] > 100)
                        {
                            datah[x]++;
                            datav[y]++;
                        }
                    }
                }
            }

            
            m_Bitmap.UnlockBits(bitmapdata);
            string result = BMUtility.IntsToString(datah);
            result += ";";
            result += BMUtility.IntsToString(datav);
 
            return result;
        }

        public List<MatchResult> Match(WaveItem item)
        {
            Graphics g = Graphics.FromImage(m_Bitmap);
            g.Clear(Color.Black);
            item.DrawToBitmap(m_Bitmap, m_Pen);

            int[] datah = new int[m_Bitmap.Width];
            int[] datav = new int[m_Bitmap.Width];

            BitmapData bitmapdata = m_Bitmap.LockBits(new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height), ImageLockMode.ReadOnly, m_Bitmap.PixelFormat);

            unsafe
            {
                byte* bits = (byte*)bitmapdata.Scan0;

                for (int x = 0; x < bitmapdata.Width; x++)
                {
                    for (int y = 0; y < bitmapdata.Height; y++)
                    {
                        int index = y * bitmapdata.Stride + x * 3;
                        if (bits[index] > 100)
                        {
                            datah[x]++;
                            datav[y]++;
                        }
                    }
                }
            }
            m_Bitmap.UnlockBits(bitmapdata);


            List<MatchResult> result = new List<MatchResult>();
            double min = 999999;
            int id = -1;
            int qid = -1;
            foreach (WaveDataSet.labelsRow row in m_Manager.Dataset.labels)
            {
                double ds1 = ComputeFinger(item.FingerData, row);
                double ds2 = ComputeDS(datah, datav, row);// +ComputeFinger(item.FingerData, row) * 2; 
                Debug.WriteLine(string.Format("<<<<<<<<<{0}               {1}",ds1,ds2));
                double ds = ds2+ds1*50;
                if (ds < min)
                {
                    min = ds;
                    id = row.name_id;
                    qid = row.quality_id;
                }
            }

            MatchResult mr = new MatchResult();
            mr.NameID = id;
            mr.Weight = 0;
            result.Add(mr);
            item.TypeID = id;
            item.QualityID = qid;
            
            return result;
        }
        private double ComputeDS(int[] h, int[] v, WaveDataSet.labelsRow row)
        {
            string[] hv = row.finger_data.Split(';');
            if (hv.Length != 2)
                return 9999;
            int[] h2 = BMUtility.StringToInts(hv[0]);
            int[] v2 = BMUtility.StringToInts(hv[1]);

            if (h2.Length != h.Length) return 9999;
            if (v2.Length != v.Length) return 9999;

            double d1 = 0;
            double d2 = 0;
            
            for (int i = 1; i < h2.Length; i++)
            {
                double td1 = h[i] - h[i - 1];
                double td2 = h2[i] - h2[i - 1];
                d1 += (h[i] - h2[i]) * (h[i] - h2[i]);
            }
            for (int i = 1; i < h2.Length; i++)
            {
                double td1 = v[i] - v[i - 1];
                double td2 = v2[i] - v2[i - 1];
                d2 +=  (v[i] - v2[i]) * (v[i] - v2[i]);
            }
            
            return (d1+d2);
        }
        private double ComputeFinger(double[] data, WaveDataSet.labelsRow row)
        {
            double[] finger = BMUtility.StringToDoubles(row.graphics_data);
            if (finger.Length != data.Length) return 9999999;
            double r = 0;
            for (int i = 0; i < data.Length; i++)
            {
                r += (data[i] - finger[i]) * (data[i] - finger[i]);
            }
            r = Math.Sqrt(r);
            return r;
        }
    }
}
